//
// Created by imed on 2024/4/1.
//

#include "IntervalConvert.h"

namespace ThirdExtendIntervalConst{
    THIRD_EXTEND_PAIR SQL_NAME = std::make_pair("SQL_NAME", "interval-convert.sqlite3");
    THIRD_EXTEND_PAIR FROM_PATH = std::make_pair("FROM_PATH", "");
    THIRD_EXTEND_PAIR TO_PATH = std::make_pair("TO_PATH", "");
    THIRD_EXTEND_PAIR DST_NAME_TEMPLATE = std::make_pair("DST_NAME_TEMPLATE", "_Non_myd_{}_001.jpg");
    THIRD_EXTEND_PAIR LEFT_IDENTY = std::make_pair("LEFT_IDENTY", "L");
    THIRD_EXTEND_PAIR RIGHT_IDENTY = std::make_pair("RIGHT_IDENTY", "R");
    THIRD_EXTEND_PAIR LOOP_INTERVAL = std::make_pair("LOOP_INTERVAL", "3");
}


int ThirdExtendIntervalConvert::initModule(std::string modulePath,
                                           std::string capturePath,
                                           std::string convertPath,
                                           bool force) {
    path mP(std::experimental::filesystem::u8path(modulePath));
    path bP = mP / "IntervalConvertMain.exe";
    path yP = mP / "AppConfig.yaml";
    path cP = mP / "runtime-cache";
    ThirdExtendIntervalConst::FROM_PATH.second = capturePath;
    ThirdExtendIntervalConst::TO_PATH.second = convertPath;

    if(force) deleteCache(cP);
    if (!genYaml(yP.string())) return -1;
    return startBinary(bP.string());
}

void ThirdExtendIntervalConvert::deleteCache(path cachePath) {
    std::cout << "Delete cache file: " << std::filesystem::remove_all(cachePath) << std::endl;
}

bool ThirdExtendIntervalConvert::destoryModule(int pid) {
    if (pid == -1) return true;

    HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
    if (hProcess != NULL) {
        if (TerminateProcess(hProcess, 0)) {
            CloseHandle(hProcess);
            std::cout << "Process terminated successfully." << std::endl;
            return true;
        } else {
            CloseHandle(hProcess);
            std::cerr << "Failed to terminate process." << std::endl;
            return false;
        }
    } else {
        std::cerr << "Failed to open process." << std::endl;
        return false;
    }
}

void ThirdExtendIntervalConvert::writeStringToFile(std::ofstream &outStream, std::string key, std::string value) {
    outStream << key << ": " << value << std::endl;
}

bool ThirdExtendIntervalConvert::genYaml(std::string yamlPath) {
    try{
        std::ofstream fout(yamlPath, std::ios::out | std::ios::trunc);
        fout << "#This file was generate by cpp wrapper" << std::endl;
        writeStringToFile(fout, ThirdExtendIntervalConst::SQL_NAME.first, ThirdExtendIntervalConst::SQL_NAME.second);
        writeStringToFile(fout, ThirdExtendIntervalConst::FROM_PATH.first, ThirdExtendIntervalConst::FROM_PATH.second);
        writeStringToFile(fout, ThirdExtendIntervalConst::TO_PATH.first, ThirdExtendIntervalConst::TO_PATH.second);
        writeStringToFile(fout, ThirdExtendIntervalConst::DST_NAME_TEMPLATE.first, ThirdExtendIntervalConst::DST_NAME_TEMPLATE.second);
        writeStringToFile(fout, ThirdExtendIntervalConst::LEFT_IDENTY.first, ThirdExtendIntervalConst::LEFT_IDENTY.second);
        writeStringToFile(fout, ThirdExtendIntervalConst::RIGHT_IDENTY.first, ThirdExtendIntervalConst::RIGHT_IDENTY.second);
        writeStringToFile(fout, ThirdExtendIntervalConst::LOOP_INTERVAL.first, ThirdExtendIntervalConst::LOOP_INTERVAL.second);
        fout.close();
    }catch (const std::exception &e){
        std::cerr << "Create yaml error: " << e.what() << std::endl;
        return false;
    }

    return true;
}

int ThirdExtendIntervalConvert::startBinary(std::string binaryPath) {
    SHELLEXECUTEINFO hProcess = {0};
    hProcess.cbSize = sizeof(SHELLEXECUTEINFO);
    hProcess.fMask = SEE_MASK_NOCLOSEPROCESS;
    hProcess.hwnd = NULL;
    hProcess.lpVerb = NULL;
    hProcess.lpFile = binaryPath.c_str();
    hProcess.lpParameters = "";
    hProcess.lpDirectory = NULL;
    hProcess.nShow = SW_SHOWNORMAL;
    hProcess.hInstApp = NULL;

    if (!ShellExecuteEx(&hProcess)) {
        std::cerr << GetLastError() << std::endl;
        return -1;
    } else {
        DWORD dwId = GetProcessId(hProcess.hProcess);
        std::cout << "Get process ID: " <<  dwId << std::endl;
        return (int)dwId;
    }
}
